using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.WowAddonStudio.FrameXml.Components;

namespace Microsoft.WowAddonStudio.FrameXml.Components.Support
{
	public sealed class LayoutImageList
	{
		private static readonly ImageList treeViewImages = new ImageList();
		private static readonly Dictionary<Type, int> typeImageMap = new Dictionary<Type, int>();

		/// <summary>
		/// Initializes a new instance of the <see cref="LayoutImageList"/> class.
		/// </summary>
		private LayoutImageList()
		{
		}

		/// <summary>
		/// Gets the default images.
		/// </summary>
		/// <value>The default images.</value>
		public static ImageList DefaultImages
		{
			get
			{
				InitializeDefaults();
				return treeViewImages;
			}
		}

		/// <summary>
		/// Gets the default images.
		/// </summary>
		/// <value>The default images.</value>
		public static ImageList DefaultStateImages
		{
			get
			{
				var imageList = new ImageList();
				imageList.Images.AddRange(new Image[] { Resources.Nok, Resources.Ok });
				return imageList;
			}
		}

		/// <summary>
		/// Initializes the defaults.
		/// </summary>
		public static void InitializeDefaults()
		{
			try
			{
				if (treeViewImages.Images.Count == 0)
					GetDefaultImages();
			}
			catch (Exception e)
			{
				Trace.WriteLine(e);
			}
		}

		/// <summary>
		/// Gets the index of the image.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		public static int GetImageIndex(string text)
		{
			KeyValuePair<Type, int> mapItem = typeImageMap.Where
				(item => item.Key.FullName.ToLower().Contains(text.ToLower())).FirstOrDefault();
			return mapItem.Value;
		}

		/// <summary>
		/// Gets the index of the image.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <returns></returns>
		public static int GetImageIndex(Type type)
		{
			int index;
			if(!typeImageMap.TryGetValue(type, out index))
			{
				index = typeImageMap[typeof (LayoutImageList)];
			}
			return index;
		}

		/// <summary>
		/// Gets the images for TreeViewControl.
		/// </summary>
		private static void GetDefaultImages()
		{
			treeViewImages.ImageSize = new Size(16, 16);
			treeViewImages.TransparentColor = Color.Magenta;
			//Add default bitmap
			AddImageFormResource(typeof(Process), "Process.bmp", typeof(LayoutImageList));
			//Add FrameXml ToolboxBitmaps
			try
			{
				Assembly assembly = Assembly.GetExecutingAssembly();
				var componentTypes = assembly.GetTypes().Where(type => IsImplementInterface(type, typeof (IFrameXmlControl)));
				foreach (Type componentType in componentTypes)
				{
					var attributes = componentType.GetCustomAttributes(false);
					if(attributes.Length > 0)
					{
						foreach (var attribute in attributes)
						{
							if(attribute is ToolboxBitmapAttribute)
							{
								var toolboxBitmapAttribute = attribute as ToolboxBitmapAttribute;
								AddImageFormResource(typeof(Button), toolboxBitmapAttribute, componentType);	
							}
						}
					}
				}
			}
			catch (Exception e)
			{
				Trace.WriteLine(e);
			}
		}

		#region Reflection, Resources and I/O Helpers

		/// <summary>
		/// Determines whether [is implement interface] [the specified component type].
		/// </summary>
		/// <param name="componentType">Type of the component.</param>
		/// <param name="interfaceType">Type of the interface.</param>
		/// <returns>
		/// 	<c>true</c> if [is implement interface] [the specified component type]; otherwise, <c>false</c>.
		/// </returns>
		private static bool IsImplementInterface(Type componentType, Type interfaceType)
		{
			var typeFilter = new TypeFilter(delegate(Type typeObj, Object criteriaObj)
			                                	{
			                                		if (typeObj.ToString() == criteriaObj.ToString())
			                                		{
			                                			return true;
			                                		}
			                                		return false;
			                                	});
			Type[] interfaces = componentType.FindInterfaces(typeFilter, interfaceType.FullName);

			return interfaces.Length > 0;
		}


		/// <summary>
		/// Adds the image form resource.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="attribute">The attribute.</param>
		/// <param name="framXmlType">Type of the fram XML.</param>
		private static void AddImageFormResource(Type type, ToolboxBitmapAttribute attribute,Type framXmlType)
		{
			Image image = attribute.GetImage(type);

			if (image != null)
			{
				treeViewImages.Images.Add(image);
				typeImageMap.Add(framXmlType, treeViewImages.Images.Count - 1);
			}
		}

		/// <summary>
		/// Adds the image form resource.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="imageName">Name of the image.</param>
		/// <param name="framXmlType">Type of the fram XML.</param>
		private static void AddImageFormResource(Type type, string imageName, Type framXmlType)
		{
			Image image = ToolboxBitmapAttribute.GetImageFromResource(type, imageName, false);

			if (image != null)
			{
				treeViewImages.Images.Add(image);
				typeImageMap.Add(framXmlType, treeViewImages.Images.Count -1);
			}
		}

		#endregion
	}
}